﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OxyPlot;

namespace AutoCorrelatorGUI.Model
{
   public class Well_Input
   {
      public Well_Input()
      {
         Data = new List<DataPoint>();
         Stats = new WellStats();
      }

      public double VarianceFunction { get; private set; }

      public List<DataPoint> Data { get; private set; }

      public WellStats Stats { get; private set; }

      private List<double> AutoCorrelate(List<double> RawData)
      {
         List<double> corrData = new List<double>();

         double mean = 0.0;
         VarianceFunction = 0.0;

         //First calculate the mean
         for (int i = 0; i < RawData.Count; i++)
         {
            mean += RawData[i];
         }

         mean /= (double)RawData.Count;

         for (int i = 0; i < RawData.Count; i++)
         {
            double diff = RawData[i] - mean;

            VarianceFunction += (diff * diff);
         }

         VarianceFunction /= (double)RawData.Count;

         for (int h = 0; h < RawData.Count; h++)
         {
            double Ch = 0.0;

            //For each shift, calculate Ch
            for (int i = 0; i < RawData.Count - h; i++)
            {
               Ch += (RawData[i] - mean) * (RawData[(i + h) % RawData.Count] - mean);
            }

            Ch /= (double)RawData.Count;

            corrData.Add(Ch);
         }

         //Mirror all but the first entry
         List<double> reversed = corrData.GetRange(1, corrData.Count - 1);
         reversed.Reverse();

         corrData.InsertRange(0, reversed);

         return corrData;
      }

      public void ProcessRawData(List<double> RawData)
      {
         List<double> corrData = null;

         if (Properties.Settings.Default.PerformAutoCorrelation)
         {
            //Properly turn the raw data into symmetric auto correlated data
            corrData = AutoCorrelate(RawData);
         }
         else
         {
            corrData = RawData;
         }

         //Remove any duplicate zeros on the ends and determine the proper shift
         int firstZero = -1;
         int lastZero = -1;

         //Trim trailing duplicate zeros
         for (int i = 0; i < corrData.Count; i++)
         {
            if (firstZero == -1 && corrData[i] != 0.0)
            {
               firstZero = i;
            }

            if (lastZero != -1)
            {
               //Reset because we have a nonzero number
               if (corrData[i] != 0.0)
                  lastZero = -1;
            }
            else if (firstZero != -1 && corrData[i] == 0.0)
            {
               lastZero = i;
            }
         }

         //Remove outsize the indices
         List<double> tempRaw = new List<double>(corrData);

         if (lastZero != -1 && lastZero < tempRaw.Count - 2)
         {
            lastZero++;
            tempRaw.RemoveRange(lastZero, tempRaw.Count - lastZero);
         }

         if (firstZero != -1 && firstZero != 0)
            tempRaw.RemoveRange(0, firstZero - 1);

         int shift = 0;

         double currentMax = Double.NegativeInfinity;

         //Even number means we need to find the peak and set that 0 to 0
         for (int i = 0; i < tempRaw.Count; i++)
         {
            if (tempRaw[i] > currentMax)
            {
               currentMax = tempRaw[i];
               shift = i;
            }
         }

         Data.Clear();

         for (int i = 0; i < tempRaw.Count; i++)
         {
            Data.Add(new DataPoint(i - shift, tempRaw[i]));
         }

         //Calculate the stats on the data
         Stats.Calc(Data);
      }
   }
}
